<template>
  <div class="board" @mousemove="drag" @mouseup="drop">
    <div class="map">
      <div>
        <svg
          v-for="cell in map"
          :key="cell.id"
          class="map-cell"
          :style="{ left: cell.pos.x + 'px', top: cell.pos.y + 'px' }"
          @click="target(cell)"
          @mouseenter="point(cell)"
          @mouseleave="point(null)">
          <polygon points="0 69.28, 40 0, 120 0, 160 69.28, 120 138.56, 40 138.56" fill="orange" />
        </svg>
      </div>
      <div>
        <Piece
          v-for="piece in pieces"
          :key="piece.id"
          class="map-piece"
          :class="{ pointing: pointing == piece, target: targets[piece.id] }"
          :style="{ left: piece.pos.x + 'px', top: piece.pos.y + 'px' }"
          :type="piece.type"
          :count="piece.count"
          @mouseenter="point(piece, true)"
          @mouseleave="point(null)"
          @click="target(piece)" />
      </div>
      <div>
        <Piece
          v-if="aniPiece"
          class="map-piece"
          :style="aniPiece.pos ? { left: aniPiece.pos.x + 'px', top: aniPiece.pos.y + 'px' } : null"
          :type="aniPiece.type"
          :count="1" />
      </div>
    </div>
    <div class="o-left">
      <div class="row">
        <Piece
          v-for="k in oHandCount"
          :key="k"
          class="row-piece"
          :type="-1"
          :count="1" />
      </div>
      <div>袋子 抢先手</div>
    </div>
    <div class="o-right">
      <div class="row discard">
        <Piece
          v-for="(piece, k) in oDiscard"
          :key="k"
          class="row-piece"
          :type="piece.type"
          :count="piece.count" />
      </div>
      <div class="row">
        <Piece
          v-for="(piece, k) in oSupply"
          :key="k"
          class="row-piece"
          :type="piece.type"
          :count="piece.count" />
      </div>
    </div>
    <div class="left">
      <div>袋子 抢先手</div>
      <div class="row">
        <Piece
          v-for="piece in hand"
          :key="piece.id"
          class="row-piece hand-piece"
          :class="{ selected: selected == piece }"
          :style="piece.pos ? { left: piece.pos.x + 'px', top: piece.pos.y + 'px' } : null"
          :type="piece.type"
          :count="1"
          @mousedown="select($event, piece)" />
      </div>
    </div>
    <div class="right">
      <div class="row">
        <Piece
          v-for="(piece, k) in supply"
          :key="k"
          class="row-piece supply-piece"
          :class="{ 'supply-pointing': pointing == piece }"
          :type="piece.type"
          :count="piece.count"
          @mouseenter="point(piece)"
          @mouseleave="point(null)" />
      </div>
      <div
        class="row discard"
        :class="{ 'discard-pointing': pointing?.id == 0 }"
        @mouseenter="point({ id: 0 })"
        @mouseleave="point(null)">
        <Piece
          v-for="(piece, k) in discard"
          :key="k"
          class="row-piece"
          :type="piece.type"
          :count="piece.count" />
      </div>
    </div>
  </div>
</template>

<script>
import Piece from './Piece'
const MAP = [
  [0, 0, 1, 1, 0, 0, 0],
  [0, 0, 1, 1, 1, 0, 0],
  [0, 1, 1, 1, 1, 0, 0],
  [0, 1, 1, 1, 1, 1, 0],
  [1, 1, 1, 1, 1, 1, 0],
  [1, 1, 1, 1, 1, 1, 1],
  [1, 1, 1, 1, 1, 1, 0],
  [0, 1, 1, 1, 1, 1, 0],
  [0, 1, 1, 1, 1, 0, 0],
  [0, 0, 1, 1, 1, 0, 0],
  [0, 0, 1, 1, 0, 0, 0]
]
function getPos(xi, yi) {
  return { x: 131.44 * xi, y: 150 * yi + 75 * (1 - xi % 2) }
}
function wait(ms) {
  return new Promise(r => setTimeout(r, ms))
}

export default {
  components: {
    Piece
  },
  data() {
    const map = []
    for (let i = 0; i < MAP.length; i++) {
      const col = MAP[i]
      for (let j = 0; j < col.length; j++) {
        if (MAP[i][j]) {
          map.push({ id: -(map.length + 1), pos: getPos(i, j) })
        }
      }
    }
    return {
      map,
      state: 1, // 0: wait, 1: main, 2: target, 3: special
      pieces: { // 棋盘上的币
        1: { id: 1, type: 1, count: 1, pos: { x: 525.76, y: 75 } },
        2: { id: 2, type: 2, count: 2, pos: { x: 657.2, y: 450 } }
      },
      hand: [ // 手上的币
        { id: 101, type: 1 },
        { id: 102, type: 2 },
        { id: 103, type: 3 }
      ],
      supply: [ // 供应堆的币
        { id: 201, type: 1, count: 1 },
        { id: 202, type: 2, count: 2 },
        { id: 203, type: 3, count: 3 }
      ],
      discard: [ // 弃牌堆的币
        { type: 1, count: 3 },
        { type: 2, count: 2 },
        { type: 3, count: 1 }
      ],
      oHandCount: 3, // 对方手上的币的数量
      oSupply: [
        { id: 1201, type: 4, count: 1 },
        { id: 1202, type: 5, count: 2 },
        { id: 1203, type: 6, count: 3 }
      ], // 对方供应堆的币
      oDiscard: [
        { type: 4, count: 1 },
        { type: 5, count: 2 },
        { type: -1, count: 3 }
      ], // 对方弃牌堆的币
      canPoint: {}, // 手上的币（非常规目标）的合法的目标
      targets: {}, // target状态下，合法的目标
      selected: null, // 抓起的手上的币
      pointing: null, // 抓起拖动时指向的目标
      aniPiece: null, // 用于动画的币
      handlingMessage: false,
      waitingMessages: [],
    }
  },
  methods: {
    select(e, piece) { // 抓起
      if (this.state != 1 && this.state != 3 ||
          this.selected ||
          this.state == 3 && !piece.special) {
        return
      }
      piece.startPos = { x: e.screenX, y: e.screenY }
      piece.pos = { x: 0, y: 0 }
      this.selected = piece
    },
    drag(e) { // 抓起后拖动
      if (!this.selected) {
        return
      }
      this.selected.pos.x = (e.screenX - this.selected.startPos.x) / this.$root.scale
      this.selected.pos.y = (e.screenY - this.selected.startPos.y) / this.$root.scale
    },
    drop() { // 放下
      if (!this.selected) {
        return
      }
      if (this.pointing) {
        console.log(this.pointing.id)
      }
      this.selected.startPos = null
      this.selected.pos = null
      this.selected = null
      this.pointing = null
    },
    point(piece, typed) { // 抓起拖动时指向
      if (!this.selected) {
        return
      }
      if (piece) {
        if (this.canPoint[this.selected.id]) {
          if (!this.canPoint[this.selected.id][piece.id]) {
            return
          }
        } else {
          if (piece.id < 0 && !piece.occupied ||
              typed && piece.type != this.selected.type) {
            return
          }
        }
      }
      this.pointing = piece
    },
    target(piece) { // 点击
      if (this.state != 2 || !this.targets[piece.id]) {
        return
      }
      console.log(piece.id)
    },
    async handleMessage(message) {
      if (this.handlingMessage) {
        this.waitingMessages.push(message)
        return
      }
      this.handlingMessage = true
      switch (message.type) {
        case 'turn':
          /*
            {
              type: 'turn'
              canPoint: any
            }
          */
          this.state = 1
          this.canPoint = message.canPoint
          break
        case 'play':
          /*
            {
              type: 'play'
              index: number
              piece: {
                xIndex: number
                yIndex: number
                type: number
              }
              discard: boolean
            }
          */
          if (!this.hand[message.index]) {
            console.log('play: hand[message.index] == null')
            break
          }
          this.hand.splice(message.index, 1)
          this.aniPiece = message.piece
          await wait(50)
          this.aniPiece.pos = getPos(this.aniPiece.xIndex, this.aniPiece.yIndex)
          await wait(900)
          if (message.discard) {
            const dis = this.discard.find(p => p.type == this.aniPiece.type)
            if (dis) {
              dis.count++
            } else {
              this.aniPiece.count = 1
              this.discard.push(this.aniPiece)
            }
          }
          this.aniPiece = null
          await wait(50)
          break
        case 'oplay':
          /*
            {
              type: 'oplay'
              piece: {
                xIndex: number
                yIndex: number
                type: number
              }
              discard: boolean
            }
          */
          if (this.oHandCount <= 0) {
            console.log('oplay: oHandCount <= 0')
            break
          }
          this.oHandCount--
          this.aniPiece = message.piece
          await wait(50)
          this.aniPiece.pos = getPos(this.aniPiece.xIndex, this.aniPiece.yIndex)
          await wait(900)
          if (message.discard) {
            const dis = this.oDiscard.find(p => p.type == this.aniPiece.type)
            if (dis) {
              dis.count++
            } else {
              this.aniPiece.count = 1
              this.oDiscard.push(this.aniPiece)
            }
          }
          this.aniPiece = null
          await wait(50)
          break
        case 'move':
          /*
            {
              type: 'move'
              id: number
              to: {
                xIndex: number
                yIndex: number
              }
            }
          */
          {
            const piece = this.pieces[message.id]
            if (!piece) {
              console.log('move: pieces[message.id] == null')
              break
            }
            await wait(50)
            piece.pos = getPos(message.to.xIndex, message.to.yIndex)
            await wait(950)
          }
          break
        case 'remove':
          /*
            {
              type: 'remove'
              id: number
            }
          */
          {
            const piece = this.pieces[message.id]
            if (!piece) {
              console.log('remove: pieces[message.id] == null')
              break
            }
            if (piece.count > 1) {
              piece.count--
              this.aniPiece = {
                type: piece.type,
                pos: {
                  x: piece.pos.x,
                  y: piece.pos.y
                }
              }
              await wait(50)
              this.aniPiece.pos.x += 1000
              await wait(900)
              this.aniPiece = null
            } else {
              await wait(50)
              piece.pos.x += 1000
              await wait(900)
              delete this.pieces[message.id]
            }
            await wait(50)
          }
          break
        default:
          console.log('Unknown message: ' + message.type)
      }
      this.handlingMessage = false
      if (this.waitingMessages.length) {
        this.handleMessage(this.waitingMessages.shift())
      }
    }
  }
}
</script>

<style scoped>
.board {
  position: absolute;
  background-color: wheat;
  display: flex;
  justify-content: center;
  align-items: center;
}

.map {
  position: relative;
  margin-left: 20px;
  width: 1474.4px;
  height: 1038.56px;
}

.map-cell {
  position: absolute;
}

.map-piece {
  position: absolute;
  left: 0;
  top: 0;
  transform: translate(20px, 9.28px);
  transition: left 0.5s, top 0.5s, box-shadow 0.1s;
}

.pointing {
  box-shadow: 0 0 10px 10px lime;
}

.target {
  box-shadow: 0 0 10px 10px yellow;
}

.row {
  display: flex;
  padding: 10px;
}

.row + .row {
  margin-top: 20px;
}

.right .row,
.o-right .row {
  justify-content: flex-end;
}

.row-piece + .row-piece {
  margin-left: 10px;
}

.o-left {
  position: absolute;
  left: 10px;
  top: 10px;
}

.o-right {
  position: absolute;
  right: 10px;
  top: 10px;
}

.left {
  position: absolute;
  left: 10px;
  bottom: 10px;
}

.hand-piece {
  left: 0;
  top: 0;
  transition: box-shadow 0.1s, left 0.1s, top 0.1s;
}

.selected {
  transition: box-shadow 0.1s;
  box-shadow: 0 0 10px 10px yellow;
  pointer-events: none;
}

.right {
  position: absolute;
  right: 10px;
  bottom: 10px;
}

.supply-piece {
  transition: box-shadow 0.1s;
}

.supply-pointing {
  box-shadow: 0 0 10px 10px orange;
}

.discard {
  border: 5px dashed gray;
  transition: box-shadow 0.1s;
}

.discard-pointing {
  box-shadow: 0 0 10px 10px orange inset;
}
</style>
